/*
 * ====================================================================
 * Copyright (c) 2009-2010 Quintilis31 Private Limited, Chennai, India
 * All rights reserved
 * ====================================================================
 */
package com.quintilis31.home.common.utils;

//imports for all java related files
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;

//imports for the apache loggging facility
import org.apache.commons.logging.*;

/**
 * A singleton Utility to load a properties file generically
 *
 * @author  Jothi Shankar Kumar. S
 * @version 1.0
 * @since   21-Nov-2009
 */
public final class ResourceUtil {

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance()
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder {
      private static final ResourceUtil RESOURCE_UTIL = new ResourceUtil();
    }

	/** This would be a singleton and no instantiation from outside */
	private ResourceUtil() {
	}

    /**
     * This method returns the singleton instance
     * @return   the singleton instance
     */
    public ResourceUtil getResourceUtil() {
        return SingletonHolder.RESOURCE_UTIL;
    }

    /** The logger instance. */
    private static final Log logger = LogFactory.getLog(ResourceUtil.class);

    /**
     * Load properties from the given name. Try loading these properties in the following order, (1) load as XML
     * properties from the classpath; (2) load as NVP properties from the classpath; (3) load as XML properties from the
     * file system; (4) load as NVP properties from the file system; If all above fail then throw IOException.
     *
     * @param name  properties name
     * @return      Properties
     * @throws      IOException - IOException in case of failure
     */
    public static Properties getAsProperties(final String name) throws IOException {
        Properties props = new Properties();
        // try loading via URL from the CLASSPATH
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL url = classLoader.getResource(name);
        if (url != null) {
            // try XML properties, failing that try standard NVP.
            try {
                props.loadFromXML(url.openStream());
            }
            catch (InvalidPropertiesFormatException e) {
                // NOTE: we have to re-open the input stream on exception
                props.load(url.openStream());
            }
        }
        else {
            // try XML properties, failing that try standard NVP.
            try {
                props.loadFromXML(new FileInputStream(name));
            }
            catch (InvalidPropertiesFormatException e) {
                logger.debug("Exception occurred when loading from an input stream", e);
                // NOTE: we have to re-open the input stream on exception
                props.load(new FileInputStream(name));
            }
        }
        return props;
    }

    /**
     * Load given resource and return as an input stream.
     *
     * Firstly try loading from the classpath, if this fails try loading from the file system. If this fails throw an
     * IOException.
     *
     * @param name  resource name
     * @return      InputStream
     * @throws      IOException - Exception if we cannot read source
     */
    public static InputStream loadResource(final String name) throws IOException {
        // Try loading via URL from the CLASSPATH
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL url = classLoader.getResource(name);
        if (url != null) {
            return url.openStream();
        }
        // Nothing on the CLASSPATH, lets try the file system
        return new FileInputStream(name);
    }

    /**
     * Load URL from the classpath. If not found the url will be returned as null.
     *
     * @param name - resource name
     * @return URL
     */
    public static URL getAsUrl(final String name) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        return classLoader.getResource(name);
    }

    /**
     * Load URL from the classpath. If not found the url will be returned as null.
     *
     * @param name  properties name
     * @param       screamOnFail - throw an IOException if we fail to load the resource name.
     * @return      URL
     * @throws      IOException - Exception if we cannot read
     */
    public static URL getAsUrl(final String name, final boolean screamOnFail) throws IOException {
        URL url = getAsUrl(name);
        if (url == null && screamOnFail) {
            throw new IOException("Failed to load resource [" + name + "]. Not found on classpath.");
        }
        return url;
    }
}
